#!/usr/bin/python

# written by ryutlis
# email: ryutlis@ryutlism.org
# homepage: http://www.ryutlism.org
# under new BSD license

__author__='ryutlis@ryutlism.org'
__version__='alpha-v0.4'

# import modules
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
from google.appengine.api import users
import os
import sys
sys.path.insert(0, 'python-twitter-0.6.zip')
sys.path.append('python-twitter-0.6.zip/python-twitter-0.6')
import twitter

# pre-defined html
html_invalid_email="""
<p>Sorry, you cannot view this page</p>
<a href="%s">Sign out</a>
"""

html_no_user="""
<center>
<h1>Welcome</h1>
<h3>Please <a href="%s">sign in</a></h3>
</center>
"""

# get email, username and password
auth_file=open("auth.txt").read()
auth_file=auth_file.split('\n')
global email,name,passwd
email=auth_file[0]
name=auth_file[1]
passwd=auth_file[2]

# regular expression
import re
pattern=re.compile('http.?://[^\ ]+')
person=re.compile('@([a-z|A-Z|0-9|_]+):?')
friends=re.compile('<friends>(.+)</friends>')

# replace urls by hyperlinks
def uniqify_list(list):
    set={}
    map(set.__setitem__, list, [])
    return set.keys()

def urlize_link(text):
    matches=pattern.findall(text)
    matches=uniqify_list(matches)
    if (matches != ['']):
        for m in matches:
            text=text.replace(m, """<a href="%s">%s</a>""" % (m,m))
    
    matches=person.findall(text)
    matches=uniqify_list(matches)
    if (matches != ['']):
        for m in matches:
            n="@"+m
            text=text.replace(n, """@<a href="/p/%s"><b>%s</b></a>""" % (m,m))
    
    return text

# replace names by hyperlinks to their profile page
def urlize_name(Name, Screenname):
    Name=Name.replace(Name, """<a href="/p/%s">%s</a>""" % (Screenname, Name))
    return Name

# check whether two users are friends or not
def check_friends(user1, user2):
    import urllib
    try:
        result=urllib.urlopen("http://api.twitter.com/l/friendships/exists.xml?user_a=%s&user_b=%s" % (user1, user2)).read()
        result=friends.findall(result)[0]
    except:
        return "error"
    return result

# main page
class MainPage(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/html; charset=UTF-8'
        
        user=users.get_current_user()
        if user:
            if (user.email() != email): # not the right person
                self.response.out.write(html_invalid_email % users.create_logout_url("/"))
            else:
                self.response.out.write(open("index.html").read())
        else: # not logged in
            self.response.out.write( html_no_user % users.create_login_url("/"))

# post tweets to twitter
class PostMessage(webapp.RequestHandler):
    def post(self):
        user=users.get_current_user()
        if (user.email() == email):
            api=twitter.Api(username=name, password=passwd)
            api.SetUserAgent("ryutwitter")
            tweet=self.request.get('tweet')
            self.response.out.write("""<head><meta name='viewport' content='width=470' /></head>""")
            self.response.out.write("<center>")
            try:
                api.PostUpdate(tweet)
            except:
                self.response.out.write("<h2>Invalid message</h2>")
            else:
                self.response.out.write("<h2>Tweet posted</h2>")
            finally:
                self.response.out.write("<p><a href=\"/\" style='font-size:25px;text-weight:bold;'>Back</a></p></center>")
        else:
            self.response.out.write("Invalid user")
            self.response.out.write("""
                                    <a href="%s">Sign in to use twitter</a> 
                                    or <a href="%s">Sign out first</a></center>
                                    """ % (users.create_login_url("/"), users.create_logout_url("/")))

# profile page
class Profiles(webapp.RequestHandler):
    def get(self, UserName):
        user=users.get_current_user()
        if (user.email() == email):
            api=twitter.Api(username=name, password=passwd)
            profile_user=api.GetUser(UserName)
            
            # check friendship status
            ret=check_friends(name, UserName)
            if (ret=="true"):
                follow_unfollow="Unfollow"
                request_url="/friends/unfollow/%s" % UserName
            elif (ret=="false"):
                follow_unfollow="Follow"
                request_url="/friends/follow/%s" % UserName
            else:
                follow_unfollow="Cannot retrieve friendship info"
                request_url="javascript:location.reload(true)"
            
            template_values={
                "screen_name": UserName,
                "name": profile_user.name,
                "img_src": profile_user.profile_image_url,
                "description": profile_user.description,
                "website": profile_user.url,
                "follow_unfollow": follow_unfollow,
                "request_url": request_url,
            }
            path=os.path.join(os.path.dirname(__file__), "profile.html")
            self.response.out.write(template.render(path, template_values))
        else:
            self.response.out.write(html_invalid_email % users.create_login_url("/"))

# follow or unfollow people
class Friendship(webapp.RequestHandler):
    def get(self, friendstatus, UserName):
        api=twitter.Api(username=name, password=passwd)
        if (friendstatus=="follow"):
            api.CreateFriendship(UserName)
        elif (friendstatus=="unfollow"):
            api.DestroyFriendship(UserName)
        self.redirect("/p/%s" % UserName)

# load tweets from server
class LoadTweets(webapp.RequestHandler):
    def get(self):
        import re
        type=self.request.get('type')
        number=self.request.get('count')
        
        api=twitter.Api(username=name, password=passwd)
        
        try:
            if (type=='friends'):
                status=api.GetFriendsTimeline(count=int(number))
            else:
                status=api.GetUserTimeline(user=type, count=int(number))
        except:
            response=["<p>Server Error, cannot load tweets</p><p>twitter.com is not responding</p><p><a href='javascript:location.reload(true)'>Reload Tweets</a></p>"]
        else:
            response=["<ul>"]
            for s in status: # generate the user's tweets
                response.append("""<li>""")
                response.append("""<b class="user">%s</b>""" % urlize_name(s.user.name, s.user.screen_name))

                response.append("""<span class="tweet" id=%d>%s</span>""" % ( s.id, urlize_link(s.text)))
                response.append("""<small><i>%s</i></small>""" % s.created_at)
            
                response.append("""<br /><small><a onclick="retweet('%s', %d);charcount('textarea','counter')">retweet</a></small> <small><a onclick="reply('%s');charcount('textarea','counter');">reply</a></small>
                                """ % (s.user.screen_name, s.id, s.user.screen_name))
                response.append("</li>")
            response.append("</ul>")
        self.response.out.write(''.join(tuple(response)))

# create web app instance
application = webapp.WSGIApplication([('/', MainPage),
                                      ('/post_message', PostMessage), 
                                      ('/p/([^\ ]+)', Profiles), 
                                      ('/friends/(.+)/(.+)', Friendship),
                                      ('/load_tweets.*', LoadTweets)
                                     ], debug=True)

def main():
    run_wsgi_app(application)

if __name__=="__main__":
    main()
